#include "WlVideo.h"

void * playVideo(void *data)
{
    WlVideo *video = static_cast<WlVideo *>(data);
    while(video->playstatus != NULL && !video->playstatus->exit)
    {

        if(video->playstatus->seek)
        {
            av_usleep(1000 * 100);
            continue;
        }

        if(video->playstatus->pause)
        {
            av_usleep(1000 * 100);
            continue;
        }

        if(video->queue->getQueueSize() == 0)
        {
            if(!video->playstatus->load)
            {
                video->playstatus->load = true;
                video->wlCallJava->onCallLoad(CHILD_THREAD, true);
            }
            av_usleep(1000 * 100);
            continue;
        } else{
            if(video->playstatus->load)
            {
                video->playstatus->load = false;
                video->wlCallJava->onCallLoad(CHILD_THREAD, false);
            }
        }

        AVPacket *avPacket = av_packet_alloc();
        if(video->queue->getAvpacket(avPacket) != 0)
        {
            av_packet_free(&avPacket);
            av_free(avPacket);
            avPacket = NULL;
            continue;
        }

        if(av_bsf_send_packet(video->abs_ctx, avPacket) != 0)
        {
            av_packet_free(&avPacket);
            av_free(avPacket);
            avPacket = NULL;
            continue;
        }


        while(av_bsf_receive_packet(video->abs_ctx, avPacket) == 0)
        {
            double diff = video->getFrameDiffTime(NULL, avPacket);
            av_usleep(video->getDelayTime(diff) * 1000000);
            video->wlCallJava->onCallDecodeAVPacket(avPacket->size, avPacket->data);

            av_packet_free(&avPacket);
            av_free(avPacket);
            continue;
        }
        avPacket = NULL;

    }
    return 0;
}


/*
 *



  */

//--------------------------------------------------//
WlVideo::WlVideo(WlPlaystatus *playstatus, WlCallJava *wlCallJava) {
    this->playstatus = playstatus;
    this->wlCallJava = wlCallJava;
    queue = new WlQueue(playstatus);
    pthread_mutex_init(&codecMutex, NULL);
}


void WlVideo::play() {
    if(playstatus != NULL && !playstatus->exit)
    {
        pthread_create(&thread_play, NULL, playVideo, this);
    }
}


void WlVideo::release() {

    if(queue != NULL)
    {
        queue->noticeQueue();
    }

    pthread_join(thread_play, NULL);

    if(queue != NULL)
    {
        delete(queue);
        queue = NULL;
    }

    if(abs_ctx != NULL)
    {
        av_bsf_free(&abs_ctx);
        abs_ctx = NULL;
    }

    if(avCodecContext != NULL)
    {
        pthread_mutex_lock(&codecMutex);
        avcodec_close(avCodecContext);
        avcodec_free_context(&avCodecContext);
        avCodecContext = NULL;
        pthread_mutex_unlock(&codecMutex);
    }

    if(playstatus != NULL)
    {
        playstatus = NULL;
    }

    if(wlCallJava != NULL)
    {
        wlCallJava = NULL;
    }
}

WlVideo::~WlVideo() {
    pthread_mutex_destroy(&codecMutex);
}

double WlVideo::getFrameDiffTime(AVFrame *avFrame, AVPacket *avPacket) {
    double pts = 0;
    if(avFrame != NULL)
    {
        pts = av_frame_get_best_effort_timestamp(avFrame);
    }

    if(avPacket != NULL)
    {
        pts = avPacket->pts;
    }

    if(pts == AV_NOPTS_VALUE)
    {
        pts = 0;
    }

    pts *= av_q2d(time_base);

    if(pts > 0)
    {
        clock = pts;
    }

    return  audio->clock  -  clock;
}


double WlVideo::getDelayTime(double diff) {

    if(diff > 0.003)
    {
        delayTime = delayTime * 2 / 3;
        if(delayTime < defaultDelayTime / 2)
        {
            delayTime = defaultDelayTime * 2 / 3;
        }
        else if(delayTime > defaultDelayTime * 2)
        {
            delayTime = defaultDelayTime * 2;
        }
    }

    else if(diff < - 0.003)
    {
        delayTime = delayTime * 3 / 2;
        if(delayTime < defaultDelayTime / 2)
        {
            delayTime = defaultDelayTime * 2 / 3;
        }
        else if(delayTime > defaultDelayTime * 2)
        {
            delayTime = defaultDelayTime * 2;
        }
    }

    else if(diff == 0.003)
    {

    }

    if(diff >= 0.5)
    {
        delayTime = 0;
    }

    else if(diff <= -0.5)
    {
        delayTime = defaultDelayTime * 2;
    }

    if(fabs(diff) >= 10)
    {
        delayTime = defaultDelayTime;
    }
    return delayTime;
}
